package com.imooc.controller;

import com.imooc.BO.ShopCartBO;
import com.imooc.BO.UserBO;
import com.imooc.constant.RedisConstant;
import com.imooc.pojo.Users;
import com.imooc.service.UserService;
import com.imooc.utils.*;
import com.imooc.vo.UsersVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.minidev.json.JSONUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author gcq
 * @Create 2022-01-04
 */
@Api(value = "注册登录", tags = "用于注册和登录的接口")
@RestController
@RequestMapping("passport")
public class PassPortController extends BaseController {

    @Autowired
    UserService userService;

    @Autowired
    private RedisOperator redisOperator;

    /**
     * 判断用户名是否存在
     *
     * @param username 用户昵称
     * @return
     */
    @ApiOperation(value = "用户名是否存在", notes = "用户名是否存在", httpMethod = "GET")
    @GetMapping("/usernameIsExist")
    public IMOOCJSONResult userNameIsExist(@RequestParam String username) {
        // 1、判断用户名是否为空
        if (StringUtils.isBlank(username)) {
            return IMOOCJSONResult.errorMsg("用户名不能为空");
        }

        // 2、查找注册的用户名是否存在
        boolean isExist = userService.queryUserNameIsExist(username);
        if (isExist) {
            return IMOOCJSONResult.errorMsg("用户名已存在");
        }

        // 3、请求成功，用户名没有重复
        return IMOOCJSONResult.ok();
    }

    @ApiOperation(value = "用户注册", notes = "用户注册", httpMethod = "POST")
    @PostMapping("/regist")
    public IMOOCJSONResult regist(@RequestBody UserBO userBO,
                                  HttpServletRequest request,
                                  HttpServletResponse response) {
        String userName = userBO.getUsername();
        String passWord = userBO.getPassword();
        String confirmPassword = userBO.getConfirmPassword();

        if (StringUtils.isBlank(userName) ||
                StringUtils.isBlank(passWord) ||
                StringUtils.isBlank(confirmPassword)) {
            return IMOOCJSONResult.errorMsg("用户名或密码不能为空");
        }

        if (!passWord.equals(confirmPassword)) {
            return IMOOCJSONResult.errorMsg("两次密码不一致");
        }

        if (passWord.length() < 6) {
            return IMOOCJSONResult.errorMsg("密码长度不能小于6位");
        }

        // 实现用户注册
        Users user = userService.createUser(userBO);

        // 实现用户的redis会话
        UsersVO usersVO = this.convertUserVO(user);

        CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true);
        return IMOOCJSONResult.ok();
    }

    @ApiOperation(value = "用户登录", notes = "用户登录", httpMethod = "POST")
    @PostMapping("/login")
    public IMOOCJSONResult login(@RequestBody UserBO userBO, HttpServletRequest request,
                                 HttpServletResponse response) throws Exception {
        String userName = userBO.getUsername();
        String passWord = userBO.getPassword();

        if (StringUtils.isBlank(userName) ||
                StringUtils.isBlank(passWord)) {
            return IMOOCJSONResult.errorMsg("用户名和密码不能为空");
        }

        Users user = userService.queryUserForLogin(userName, MD5Utils.getMD5Str(passWord));

        if (user == null) {
            return IMOOCJSONResult.errorMsg("用户名密码不正确");
        }

        this.setNullProperty(user);

        // 生成用户token 存入redis会话
        UsersVO usersVO = this.convertUserVO(user);

        // 同步购物车数据
        this.syncShopCartData(request, response, user.getId());

        CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true);
        return IMOOCJSONResult.ok(user);
    }

    /**
     * 注册成功后，同步redis和cookie中的购物车数据
     * 1、redis中无数据，如果cookie中的购物车为空，那么这个时候不作任何处理
     *      如果cookie中购物车数据不为空，此时直接放入redis中
     * 2、redis中有数据，如果cookie中的购物车为空，那么直接把redis的购物车覆盖本地cookie中的购物车
     *      如果cooke中购物车不为空
     *      如果cookie中某个商品在redis中存在，
     *              则以cookie为主，删除redis中的，
     *              把cookie中的商品直接覆盖在redis中（参考京东）
     */
    private void syncShopCartData(HttpServletRequest request,
                                   HttpServletResponse response,
                                   String userId) {
        // 从redis中获取购物车
        String shopCartJsonRedis = redisOperator.get(RedisConstant.FOODIE_SHOP_CART + userId);
        // 从cookie中获取购物车
        String shopCartStrCookie = CookieUtils.getCookieValue(request, "shopcart", true);

        if (StringUtils.isBlank(shopCartJsonRedis)) {
            if (StringUtils.isNotBlank(shopCartStrCookie)) {
                // redis为空 cookie不为空，将购物车数据放到redis中
                redisOperator.set(RedisConstant.FOODIE_SHOP_CART + userId, shopCartStrCookie);
            }
        } else {
            // redis不为空，cookie不为空，合并cookie和redis中购物车的商品数(同一商品覆盖redis)
            if(StringUtils.isNotBlank(shopCartStrCookie)) {

                /**
                 * 前端业务场景：
                 *      用户在未登录情况下，添加商品到购物车中
                 *      会携带cookie进行登录,根据redis中购物车数据和cookie购物车数据进行合并处理
                 *      相同商品，cookie购物车商品数量直接覆盖redis
                 *      不相同商品添加到redis，然后同时更新redis和cookie中数据两者更新为一致
                 */
                /**
                 * 1、已经存在的，把cookie中对应的数量，覆盖redis 参考京东
                 * 2、该项商品标记为待删除，统一放到一个待删除list
                 * 3、从cookie中清除所有的待删除list
                 * 4、合并redis中的cookie中的数据
                 * 5、更新到reds和cookie中
                 */
                // redis中购物车数据
                List<ShopCartBO> shopCartBOListRedis = JsonUtils.jsonToList(shopCartJsonRedis, ShopCartBO.class);
                // cookie中购物车数据
                List<ShopCartBO> shopCartBOListCookie = JsonUtils.jsonToList(shopCartStrCookie, ShopCartBO.class);

                // 待删除list
                List<ShopCartBO> pendingDeleteList = new ArrayList<>();

                for (ShopCartBO redisShopCart : shopCartBOListRedis) {
                    String redisSpecId = redisShopCart.getSpecId();

                    for (ShopCartBO cookieShopCart : shopCartBOListCookie) {
                        String cookieSpecId = cookieShopCart.getSpecId();

                        // 匹配redis中是否存在该商品，如果存在更新数量
                        if(redisSpecId.equals(cookieSpecId)) {
                            // redis和cookie的购物车数据相同，覆盖购买数量，不累加参考京东
                            redisShopCart.setBuyCounts(cookieShopCart.getBuyCounts());
                            // 添加到待删除list中，用于最后删除合并
                            pendingDeleteList.add(cookieShopCart);
                        }
                    }
                }

                // 从现有cookie中删除对应覆盖的过的商品数据
                shopCartBOListCookie.removeAll(pendingDeleteList);
                // 合并两个redis
                shopCartBOListRedis.addAll(shopCartBOListCookie);
                // 更新到redis和cookie中
                CookieUtils.setCookie(request, response, "shopcart", JsonUtils.objectToJson(shopCartBOListRedis), true);
                redisOperator.set(RedisConstant.FOODIE_SHOP_CART + userId, JsonUtils.objectToJson(shopCartBOListRedis));
            } else {
                // redis不为空，cookie为空，直接将redis中数据覆盖到cookie中
                CookieUtils.setCookie(request, response, "shopcart", shopCartJsonRedis, true);
            }
        }
    }

    private void setNullProperty(Users users) {
        users.setPassword(null);
        users.setMobile(null);
        users.setEmail(null);
//        users.setId(null);
        users.setCreatedTime(null);
        users.setUpdatedTime(null);
        users.setBirthday(null);
    }


    @ApiOperation(value = "用户退出", notes = "用户退出", httpMethod = "POST")
    @PostMapping("/logout")
    public IMOOCJSONResult logout(@RequestParam String userId,
                                  HttpServletRequest request,
                                  HttpServletResponse response) {
        // 清楚Cookie
        CookieUtils.deleteCookie(request, response, "user");
        // 用户退出登录，清空购物车
        CookieUtils.deleteCookie(request, response, "shopcart");
        // 分布式会话，清除用户数据
        redisOperator.del(RedisConstant.REDIS_USER_TOKEN + userId);
        return IMOOCJSONResult.ok();
    }
}